package cn.nawang.ebeim.test.transfer;


import cn.nawang.ebeim.test.constants.Config;
import cn.nawang.ebeim.test.service.TestData;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URI;

public class TransferDownloadHandler extends SimpleChannelInboundHandler<HttpObject> {

    private static final Logger LOG = LoggerFactory.getLogger(TransferDownloadHandler.class);

    public long fileLength;// 服务端传来文件的总字节

    public long count;// 累计服务端传来文件的字节

    private File file;// 临时文件名

    private RandomAccessFile randomFile;

    private FileInfo fileInfo;

    private static final int MAX_PONG_TIMES = 10; // 定义客户端没有收到服务端的pong消息的最大次数

    private int pongTimes = 0;

    /**
     * 是否下载成功
     */
    private boolean isSuccess;

//    private String md5;

    private String errorMsg = "";

    private boolean isConnect ;

    private TransferCallback callback ;

    public TransferDownloadHandler(FileInfo fileInfo, TransferCallback callback) {
        this.fileInfo = fileInfo;
        this.callback = callback ;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                LOG.info("===客户端===(WRITER_IDLE 读超时)" + pongTimes);
            } else if (event.state() == IdleState.WRITER_IDLE) {
                if (pongTimes >= MAX_PONG_TIMES) {
                    LOG.info("===客户端===(WRITER_IDLE 写超时)" + pongTimes);
                    if (randomFile != null) {
                        randomFile.close();
                    }
                    isSuccess = false;
                    ctx.channel().close();
                } else {
                    // 失败计数器加1
                    pongTimes++;
                }
            } else if (event.state() == IdleState.ALL_IDLE) {
                /* 总超时 */
                LOG.info("===客户端===(ALL_IDLE 总超时)");
            }
        }
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        if(!isConnect()){
            callback.onTransferFailed(fileInfo,new TransferException("网络信号差,无法建立连接!"));
        }
        if(isSuccess){
            callback.onTransferSuccess(fileInfo);
        }else {
            callback.onTransferFailed(fileInfo,new TransferException("文件下载失败!" + errorMsg));
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        isConnect = true ;
        long downLength = 0;
        File file = getFile(fileInfo);
        if (file.exists() && file.isFile()) {
            downLength = file.length();
        }

        QueryStringEncoder encoder = new QueryStringEncoder("download");
        encoder.addParam("type", String.valueOf(fileInfo.getType()));
        encoder.addParam("version", fileInfo.getVersion());
        encoder.addParam("dataId", fileInfo.getDataId());
        encoder.addParam("signature", fileInfo.getSignature());
        encoder.addParam("signature", fileInfo.getSignature());
        encoder.addParam("downLength", String.valueOf(downLength));
        URI uriGet = new URI(encoder.toString());
        HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
        HttpHeaders headers = request.headers();
        headers.set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
        ctx.writeAndFlush(request);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        pongTimes = 0;
        if (msg instanceof HttpResponse) {

            HttpResponse response = (HttpResponse) msg;
            if (response.getStatus().code() == 200) {
                // 生成临时文件
                file = getFile(fileInfo);
                LOG.info("开始下载:" + file.getAbsolutePath());
//                md5 = response.headers().get("md5");
                fileLength = response.headers().getContentLength(response);
                if (fileLength == 0 && file.exists()) {
                    // 验证文件的正确性

                    isSuccess = reNameFile(file);
                    ctx.close();
                } else {
                    randomFile = new RandomAccessFile(file, "rw");
                    long downLength = randomFile.length();
                    randomFile.seek(downLength);
                }
            } else {
                errorMsg = response.headers().get("error") ;
                isSuccess = false;
            }
        }

        if (msg instanceof HttpContent && fileLength != 0) {
            HttpContent chunk = (HttpContent) msg;
            ByteBuf buf = chunk.content();
            count += buf.readableBytes();
//            if (fileInfo.getNid() != null) {
//                DownloadProcessBarList.summationTotal(fileInfo.getNid(), buf.readableBytes());
//            }
            double rate = count * 100 / fileLength;
            LOG.debug("下载进度：" + rate);
            byte[] req = new byte[buf.readableBytes()];
            buf.readBytes(req);
            // 开始写入文件内容
            randomFile.write(req);
            if (chunk instanceof LastHttpContent) {
                TestData.setTotalTransferBytes(file.length());
                randomFile.close();
                // 验证文件正确性
//                isSuccess = validateFile(file);
//                if (!isSuccess) {
//                    file.delete();
//                    LOG.info(file.getAbsolutePath() + "---删除！");
//                } else {
//                    // 验证文件的重命名
//                }
                isSuccess = reNameFile(file);
                ctx.close();
            }
        }
    }

    public boolean reNameFile(File file) {
        File lastFile = null;
        lastFile = getLastFile(fileInfo);
        boolean boolFile = false;
        try {
            if (lastFile.exists()) // 若在该目录下已经有一个文件和新文件名相同，则不允许重命名
                LOG.info(lastFile.getPath() + "已经存在！");
            else {
                boolFile = file.renameTo(lastFile);
            }
            if (boolFile) {
                LOG.info("客户端已成功下载文件，保存路径：" + lastFile.getPath());
            } else {
                errorMsg = "重命名失败，文件名：" + file ;
            }
        } catch (Exception e) {
            LOG.info(e.getMessage());
            e.printStackTrace();
        }
        return boolFile;
    }



    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        IOUtils.closeQuietly(randomFile);
        cause.printStackTrace();
        ctx.channel().close();
    }

    public static File getFile(FileInfo info) {
        String downloadPath = Config.DOWNLOAD_DIR ;
        File downDir = new File(downloadPath);
        String tempFilePath = downloadPath + File.separator + info.getPath()+".temp";
        if(!downDir.exists()){
            downDir.mkdirs();
        }
        File tempFile = new File(tempFilePath);
        if(!tempFile.exists()){
            tempFile.getParentFile().mkdirs();
        }

        return tempFile ;

//        String fileName = null;
//        File dir = null;
//        byte type = info.getType();
//        if (type == FileInfo.TYPE_FILE_DOWNLOAD) {
//            fileName = info.getSignature();
//            dir = new File(FileUtil.getDownloadDataFilePath(info.getDataId()));
//        } else if (type == FileInfo.TYPE_VERSION_DOWNLOAD) {
//            fileName = info.getVersion();
//            dir = new File(FileUtil.getZipVersionFilePath(info.getDataId(), ""));
//        }
//        if (!dir.getParentFile().exists()) {
//            dir.getParentFile().mkdirs();
//        }
//        // 生成临时文件名
//        File file = new File(dir + File.separator + ClientConfiguration.getTempFilePrefix() + fileName);
//        if (!file.getParentFile().exists()) {
//            file.getParentFile().mkdir();
//        }
//        return file;
//        return null ;
    }

    public File getLastFile(FileInfo info) {
        String downloadPath = Config.DOWNLOAD_DIR ;
        File downDir = new File(downloadPath);
        String tempFilePath = downloadPath + File.separator + info.getPath();
        if(!downDir.exists()){
            downDir.mkdirs();
        }
        File tempFile = new File(tempFilePath);
        if(!tempFile.exists()){
            tempFile.getParentFile().mkdirs();
        }
        return tempFile ;

//        String fileName = null;
//        File dir = null;
//        byte type = info.getType();
//        if (type == FileInfo.TYPE_FILE_DOWNLOAD) {
//            fileName = info.getSignature();
//            dir = new File(FileUtil.getDownloadDataFilePath(info.getDataId()));
//        } else if (type == FileInfo.TYPE_VERSION_DOWNLOAD) {
//            fileName = info.getVersion() + ".zip";
//            dir = new File(FileUtil.getZipVersionFilePath(info.getDataId(), ""));
//        }
//        if (!dir.getParentFile().exists()) {
//            dir.getParentFile().mkdirs();
//        }
        // 最终生成的文件
//        File lastFile = new File(dir + File.separator + fileName);
//        return lastFile;

    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public boolean isConnect() {
        return isConnect;
    }

    public boolean isSuccess() {
        return isSuccess;
    }

}
